package gioco;

import java.util.LinkedList;
import java.util.Random;

import elementi.Energia;
import elementi.Muro;
import elementi.Scudo;
import elementi.giocatori.Giocatore;


public class GestoreCampo {

	
//Ricordarsi nel Main di istanziare prima i muri e poi i giocatori,
//altrimenti i giocatori vengono considerati come muri.
	
	/*Codici per creazione griglia:
	valore 0: Zona libera
	valore 1: zona occupata
	valore 2: zona adiacente al muro*/
	
	private int[][] griglia;
	public static final int TIPI_DI_MURO = 3;
	/*public static final int DISTANZA_MINIMA = 35;*/
	
	public static final int CODICE_BIOBOT = 0;
	public static final int CODICE_BOMBOBOT = 1;
	public static final int CODICE_FASTBOT = 2;
	public static final int CODICE_TECHNOBOT = 3;
	
//Il numero di muri, scudi e energie � determinato dalle densit� e quindi � relativo alla
//dimensione dell'arena.
	
	public static final float DENSITA_SCUDI = 0.002f;
	public static final float DENSITA_ENERGIE = 0.002f;
	public static final float DENSITA_MURI = 0.25f;
	
	int altezza, larghezza;
	int numMuri;
	int [] tipoGiocatori;
	String [] tipoGiocatoriPc;
	int righeGriglia;
	int colonneGriglia;
	
	Random random = new Random();
	
	LinkedList<Giocatore> giocatori = new LinkedList <Giocatore> ();
	LinkedList<Muro> muri = new LinkedList <Muro> ();
	LinkedList<Scudo> scudi = new LinkedList <Scudo> ();
	LinkedList<Energia> energie = new LinkedList <Energia> ();
	
/*TipoGiocatori contiene il numero di giocatori controllati manualmente (GiocatorePc), controllati tramite rete
oppure tramite intelligenza artificiale.
TipoGiocatoriPc contiene i nomi dei personaggi scelti dal menu (FastBot, Bombobot, ...; queste stringhe
sono convertite in interi dal metodo RiconosciPersonaggi e sono usati per istanziare i giocatori.*/
	
	public GestoreCampo(int larghezza, int altezza, int [] tipoGiocatori, String [] tipoGiocatoriPc) {
		super();
		this.altezza = altezza;
		this.larghezza = larghezza;
		this.colonneGriglia=(larghezza/Muro.LATO_MURO);
		this.righeGriglia=(altezza/Muro.LATO_MURO);
		this.griglia=new int[righeGriglia][colonneGriglia];
		this.tipoGiocatori = tipoGiocatori;
		this.tipoGiocatoriPc = tipoGiocatoriPc;
	}

/*Crea una griglia di interi per fare in modo che gli elementi da creare non si sovrappongano a
 * quelli gi� presenti */
	
	private boolean creaGriglia () {
		int[][] salvataggio = null;
		int areaMuriTot = Math.round(DENSITA_MURI*colonneGriglia*righeGriglia);
		int areaMuri = 0;
		int areaMuro = 0;
		int contatore = 0;
		
		//Nel caso creaGriglia non riesca a disporre i muri, anziche entrare in un ciclo infinito
		//ritorna false. In creaMuri viene resettata e viene creata un'altra griglia.
		while(areaMuri < areaMuriTot){
			contatore = 0;
			salvataggio = copiaGriglia(griglia);
			
			while((areaMuro = creaMuroRettangolare()) == 0){
				griglia = copiaGriglia(salvataggio);
				if((contatore++) > 100) return false;
			}
			
			
			areaMuri = areaMuri + areaMuro;
		}
		
		return true;
	}

//Usa la griglia di interi per creare un LinkedList di muri nella posizione corretta.
	
	public LinkedList<Muro> creaMuri(){
		while(!creaGriglia()){
			resetGriglia();
		}	
		
		
		for (int i = 0; i < righeGriglia; i++) {
			for (int j = 0; j < colonneGriglia; j++) {
				if (griglia[i][j]==1) {
					Muro muro = FactoryProxy.getFactoryElementi().creaMuro();
					muro.setX(Muro.LATO_MURO/2+Muro.LATO_MURO*j);
					muro.setY(Muro.LATO_MURO/2+Muro.LATO_MURO*i);
					muri.add(muro);
				}
			}
		}
		return muri;
	}
	
//Aggiunge alla griglia un muro rettangolare di proporzioni casuali e
// ne ritorna l'area, controllando che non sia sovrapposto ad altri. In questo caso ritorna 0.
	
	private int creaMuroRettangolare() {
		int lunghezza = random.nextInt(7) + 2;
		int altezza = random.nextInt(7) + 2;
		
		int x = random.nextInt(colonneGriglia);
		int y = random.nextInt(righeGriglia);
		
		for (int i = y - 1; i < y +lunghezza + 1; i++) {
			for (int j = x - 1; j <x + altezza + 1; j++) {
				if(i < righeGriglia && i >= 0 && j >= 0 && j<colonneGriglia){
					if(griglia[i][j] == 0){
						griglia[i][j] = 2;
					}else{
						return 0;
					}
				}
			}
		}
		
		for (int i = y; i < y +lunghezza; i++) {
			for (int j = x; j <x + altezza; j++) {
				if(i < righeGriglia && i >= 0 && j >= 0 && j<colonneGriglia){
					if(griglia[i][j] == 2){
						griglia[i][j] = 1;
					}else{
						return 0;
					}
				}
			}
		}
	
		
		return altezza*lunghezza;
	}

	
//Crea un LinkedList di giocatori, senza sovrapporli agli altri elementi.
	
	public LinkedList<Giocatore> creaGiocatori () {
		
		int i = tipoGiocatori[0];
		int j = 0;
		while (i>0) {
			int riga = random.nextInt(righeGriglia);
			int colonna = random.nextInt(colonneGriglia);
			Giocatore temp;
			
			if (griglia[riga][colonna] == 0) {
				temp = riconosciPersonaggio (tipoGiocatoriPc[j]);
				temp.setX(Muro.LATO_MURO/2+colonna*Muro.LATO_MURO);
				temp.setY(Muro.LATO_MURO/2+riga*Muro.LATO_MURO);
				giocatori.add(temp);
				griglia[riga][colonna] = 1;
				i--;
				j++;
			}
		}
		i= tipoGiocatori[1];
		while (i>0) {
			//TODO prossima gara
				i--;
		}
		i= tipoGiocatori[2];
		while (i>0) {
			//TODO prossima gara
				i--;
		}
		
		return giocatori;
	}

//Azzera la griglia nel caso il campo debba essere ricreato prima di chiudere il gioco.
	public void resetGriglia(){
		for(int i= 0 ; i <righeGriglia;i++){
			for (int j = 0; j < colonneGriglia; j++){
				griglia[i][j] = 0;
			}
		}
	}

	private Giocatore riconosciPersonaggio (String personaggio) {
		if (personaggio.equalsIgnoreCase("biobot")) {
			return FactoryProxy.getFactoryElementi().creaBiobot();
		} else if (personaggio.equalsIgnoreCase("bombobot")) {
			return FactoryProxy.getFactoryElementi().creaBombobot();
		}
		else if (personaggio.equalsIgnoreCase("fastbot")) {
			return FactoryProxy.getFactoryElementi().creaFastBot();
		}
		else if (personaggio.equalsIgnoreCase("technobot")) {
			return FactoryProxy.getFactoryElementi().creaTechnobot();
		} else {
			return FactoryProxy.getFactoryElementi().creaFastBot();
		}
	}
	
	private int[][] copiaGriglia(int[][] griglia){
		int righe = griglia.length;
		int colonne = griglia[0].length;
		
		int[][] risultato = new int[righe][colonne];
		
		for (int i = 0; i < righe; i++) {
			for (int j = 0; j < colonne; j++) {
				risultato[i][j] = griglia[i][j];
			}
		}
		
		return risultato;
		
	}
	
//Crea un LinkedList di scudi, senza sovrapporli agli altri elementi.	
	public LinkedList<Scudo> creaScudi(){
		int i = Math.round(DENSITA_SCUDI*colonneGriglia*righeGriglia);
		
		while (i>0) {
			int riga = random.nextInt(righeGriglia);
			int colonna = random.nextInt(colonneGriglia);
			Scudo temp;
			
			if (griglia[riga][colonna] == 0) {
				temp = FactoryProxy.getFactoryElementi().creaScudo(Muro.LATO_MURO/2f+colonna*Muro.LATO_MURO, Muro.LATO_MURO/2f+riga*Muro.LATO_MURO);
				scudi.add(temp);
				griglia[riga][colonna] = 1;
				i--;
			}
		}
		return scudi;
	}

//Crea un LinkedList di energie, senza sovrapporli agli altri elementi.
	public LinkedList<Energia> creaEnergie(){
		int i = Math.round(DENSITA_ENERGIE*colonneGriglia*righeGriglia);
		
		while (i>0) {
			int riga = random.nextInt(righeGriglia);
			int colonna = random.nextInt(colonneGriglia);
			Energia temp;
			
			if (griglia[riga][colonna] == 0) {
				temp = FactoryProxy.getFactoryElementi().creaEnergia(Muro.LATO_MURO/2f+colonna*Muro.LATO_MURO, Muro.LATO_MURO/2f+riga*Muro.LATO_MURO);
				energie.add(temp);
				griglia[riga][colonna] = 1;
				i--;
			}
		}
		return energie;
	}
}